#include "tile_table_view.h"

#include <QContextMenuEvent>
#include <QDebug>
#include <QFileDialog>
#include <QMenu>
#include <QPoint>

#include "app_state_model.h"
#include "pack_metadata.h"
#include "qvariant_utils.h"
#include "texture_pack.h"
#include "tile_sheet.h"
#include "tile_table_model.h"
#include "tile.h"

typedef QPair<TexturePack*, QPoint> TilePositionOverridePair;
Q_DECLARE_METATYPE(TilePositionOverridePair);

TileTableView::TileTableView(QWidget* parent)
    : QTableView(parent), app_state_model_(NULL) {
}

QString TileTableView::computedSelectionName() const {
  if (selectedIndexes().length() > 1) {
    return QString("%L1 tiles").arg(selectedIndexes().length());
  } else {
    Q_ASSERT(app_state_model_);
    const PackMetadata* metadata = app_state_model_->packMetadata();
    TileTableModel* tile_model = qobject_cast<TileTableModel*>(model());
    Q_ASSERT(tile_model);

    QModelIndex index = selectedIndexes().first();
    QString tilesheet_name = tile_model->tileSheetName();
    QString tile_name = metadata->tileName(tilesheet_name, index.row(), index.column());
    if (tile_name.isEmpty()) {
      return "Unknown Tile";
    } else {
      return tile_name;
    }
  }
}

TileTableModel* TileTableView::tileModel() const {
  TileTableModel* ret = qobject_cast<TileTableModel*>(model());
  Q_ASSERT(ret);
  return ret;
}

void TileTableView::setChosenPackHelper() {
  QAction* action = qobject_cast<QAction*>(sender());
  if (!action) {
    qWarning() << "setChosenPackHelper called with" << sender()
               << "as sender, which is not a QAction.";
    return;
  }
  TexturePack* pack = QVariantPtr<TexturePack>::asPointer(action->data());
  tileModel()->setChosenPack(selectedIndexes(), pack);
  tileModel()->clearTilePositionOverride(selectedIndexes());
  tileModel()->clearTilePixmapOverride(selectedIndexes());
}

void TileTableView::setTilePositionOverrideHelper() {
  QAction* action = qobject_cast<QAction*>(sender());
  if (!action) {
    qWarning() << "setTilePositionOverrideHelper called with" << sender()
               << "as sender, which is not a QAction.";
    return;
  }
  TilePositionOverridePair data = action->data().value<TilePositionOverridePair>();
  TexturePack* pack = data.first;
  QPoint override = data.second;
  tileModel()->setChosenPack(selectedIndexes(), pack);
  tileModel()->setTilePositionOverride(selectedIndexes().first(), override);
  tileModel()->clearTilePixmapOverride(selectedIndexes());
}

void TileTableView::setCustomPixmapHelper() {
  QString pixmap_file = QFileDialog::getOpenFileName(
      window(), QString(), QString(), "Images (*.png *.jpg *.gif)");
  if (!pixmap_file.isEmpty()) {
    QPixmap override(pixmap_file);
    tileModel()->setChosenPack(selectedIndexes(), app_state_model_->defaultTexturePack());
    tileModel()->clearTilePositionOverride(selectedIndexes());
    tileModel()->setTilePixmapOverride(selectedIndexes().first(), override);
  }
}

void TileTableView::contextMenuEvent(QContextMenuEvent* event) {
  if (selectedIndexes().isEmpty()) {
    QTableView::contextMenuEvent(event);
    return;
  }

  bool single_selection = (selectedIndexes().length() == 1);
  TileTableModel* tile_model = tileModel();

  QMenu* context_menu = new QMenu();
  context_menu->addAction(computedSelectionName())->setEnabled(false);
  context_menu->addSeparator();
  foreach (TexturePack* pack, *app_state_model_->packs()) {
    QString tilesheet_name = tile_model->tileSheetName();
    TileSheet* tilesheet = pack->tileSheetNamed(tilesheet_name);
    QAction* action = context_menu->addAction(QString("Use %1").arg(pack->name()));
    action->setData(QVariantPtr<TexturePack>::asVariant(pack));
    action->setEnabled(tilesheet != NULL);
    connect(action, SIGNAL(triggered()), SLOT(setChosenPackHelper()));
  }

  context_menu->addSeparator();

  foreach (TexturePack* pack, *app_state_model_->packs()) {
    QMenu* submenu = context_menu->addMenu(QString("Use another tile from %1").arg(pack->name()));
    submenu->setEnabled(single_selection);
    Q_ASSERT(tile_model);
    QString tilesheet_name = tile_model->tileSheetName();
    TileSheet* tilesheet = pack->tileSheetNamed(tilesheet_name);
    if (tilesheet) {
      foreach (Tile* tile, tilesheet->allTiles()) {
        if (!tile->name().isEmpty()) {
          QAction* action = submenu->addAction(tile->icon(), tile->name());
          TilePositionOverridePair pair(pack, tile->position());
          action->setData(QVariant::fromValue<TilePositionOverridePair>(pair));
          action->setEnabled(single_selection);
          connect(action, SIGNAL(triggered()), SLOT(setTilePositionOverrideHelper()));
        }
      }
    } else {
      submenu->addAction("Tilesheet missing")->setEnabled(false);
      qDebug() << "Failed to find tilesheet" << tilesheet_name << "in" << pack->name();
    }
  }

  QAction* action = context_menu->addAction("Use custom image...");
  action->setEnabled(single_selection);
  connect(action, SIGNAL(triggered()), SLOT(setCustomPixmapHelper()));
  context_menu->exec(viewport()->mapToGlobal(event->pos()));
}
